package com.cx.base.day19_thread;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @Author: robert.song
 * @Date: Created in 2021/11/29
 */

//    AQS 是指抽象类 AbstractQueuedSynchronizer
//    前面的对象锁 读锁写锁、条件产量、信号量、栅栏、自旋锁、互斥锁等都是AQS框架的衍生物
//    AQS是通过模板模式实现锁对象，当你明白其机理后可以自定义一把对象锁！
//    下面自定义一个不可重入锁
public class Thread_18_1_UnReentrantByAQS implements Lock {

    class UnReentrantByAQS extends AbstractQueuedSynchronizer {
        protected UnReentrantByAQS() {
            super();
        }

        @Override
        protected boolean tryAcquire(int arg) {
            if (compareAndSetState(0, 1)) {
//              加上锁，并且设置owner为当前线程
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
//            当前线程清空
            setExclusiveOwnerThread(null);
//            解锁，state是volatile，写下面防止重排序
            setState(0);
            return true;
        }

        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        public Condition newCondition() {
            return new ConditionObject();
        }
    }

    private UnReentrantByAQS unReentrantByAQS = new UnReentrantByAQS();

    @Override
    public void lock() {
        unReentrantByAQS.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        unReentrantByAQS.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return unReentrantByAQS.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return unReentrantByAQS.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        unReentrantByAQS.release(0);
    }

    @Override
    public Condition newCondition() {
        return unReentrantByAQS.newCondition();
    }
}
